package com.cmos.um.utils.http.config;


import com.cmos.um.utils.http.RestClientHttpRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * RestTemplate use HttpdComponentsClientHttpRequestFactory
 *
 * @author Feng Yu
 * @version V1.0
 * @date 2017-05-16
 */
@Configuration
@ConditionalOnProperty(
        name = {"um.rest.http.client.config"},
        havingValue = "on"
)
public class RestTemplateConfiguration {

    private static Logger logger = LoggerFactory.getLogger(RestClientHttpRequest.class);

    // 连接池最大连接数
    @Value("${rest.http.client.MaxTotal}")
    private int maxTotal;
    // 连接池同路由并发数
    @Value("${rest.http.client.DefaultMaxPerRoute}")
    private int defaultMaxPerRoute;
    //连接超时
    @Value("${rest.http.client.ConnectTimeout}")
    private int connectionTimeout;
    //数据读取超时时间
    @Value("${rest.http.client.ReadTimeout}")
    private int readTimeout;
    //连接不够用的等待时间
    @Value("${rest.http.client.ConnectionRequestTimeout}")
    private int connectionRequestTimeout;

    @Bean
    @ConditionalOnMissingBean({RestTemplate.class})
    public RestTemplate restTemplate2(HttpComponentsClientHttpRequestFactory clientHttpRequestFactory) {
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    @ConditionalOnMissingBean({HttpComponentsClientHttpRequestFactory.class})
    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
        try {
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            //SSL
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    return true;
                }
            }).build();
            httpClientBuilder.setSSLContext(sslContext);
            //
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
            // 注册http和https
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory).build();
            // 连接池
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            // 最大连接数
            poolingHttpClientConnectionManager.setMaxTotal(maxTotal);
            // 同路由并发数
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
            // 重试次数，默认3次未开启
            //httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));
            // httpClient连接配置
            HttpClient httpClient = httpClientBuilder.build();
            HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            // 连接超时
            clientHttpRequestFactory.setConnectTimeout(connectionTimeout);
            // 数据读取超时时间
            clientHttpRequestFactory.setReadTimeout(readTimeout);
            // 连接不够用的等待时间，不宜过长，必须设置，比如连接不够用时，时间过长将是灾难性的
            clientHttpRequestFactory.setConnectionRequestTimeout(connectionRequestTimeout);
            // 缓冲请求数据，默认值是true。通过POST或者PUT大量发送数据时，建议将此属性更改为false，以免耗尽内存。
            // clientHttpRequestFactory.setBufferRequestBody(false);
            //
            return clientHttpRequestFactory;
        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

}
